home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 …SCII & the Runetime Code / ADC Developer CD (1992-07) (''Butch ASCII And The Runtime Code'')_iso / Dev.CD 199207.iso / Tools & Apps / OS⁄Toolbox / Apple Events / AE Word Services 1.0d6 / Writeswell Jr. Source / ObText.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-23  |  20.1 KB  |  829 lines  |  [TEXT/KAHL]

  1. /* ObText.c
  2.  * ©1992 Working Software, Inc.
  3.  * This source code is copyrighted.  Permission is granted to use the Word Services
  4.  * portion of the Writeswell Jr. source code in your own programs, but you 
  5.  * may not distribute the Writeswell Jr. word-processor code as a 
  6.  * commercial product.  If you modify the code, please do not call it 
  7.  * Writeswell Jr. (or Writeswell.)  This will ensure that people understand the 
  8.  * program and don’t have to deal with a number of different versions with 
  9.  * who-knows-what going on in the code.
  10.  * 
  11.  * Writeswell Jr. and Writeswell are trademarks of Working Software, Inc.
  12.  * 26 Dec 91 Mike Crawford
  13.  */
  14.  
  15. #include <AppleEvents.h>
  16. #include <AEObjects.h>
  17. #include <AERegistry.h>
  18. #include "AppEvents.h"
  19. #include "WordServices.h"
  20. #include "ObWind.h"
  21. #include "ObText.h"
  22. #include "Gripe.h"
  23.  
  24. /* Given the the direct object of an event is a TextEdit text token (or property thereof),
  25.  * do the requested event.
  26.  */
  27.  
  28. OSErr DispatchTEText( AEDesc *tokenPtr,
  29.                         AppleEvent *theAppleEventPtr,
  30.                         AppleEvent *replyEventPtr,
  31.                         long refCon )
  32. {
  33.     OSErr            err;
  34.     AEEventClass    theClass;
  35.     AEEventID        theID;
  36.     
  37.     /* This function is only for the Core suit.  Get the event ID from the appleEvent
  38.      */
  39.     
  40.     err = GetEventID( theAppleEventPtr, &theID );
  41.     
  42.     switch ( theID ){
  43.         case kAEGetData:
  44.             err = TETextGetDataHandler( tokenPtr, theAppleEventPtr, replyEventPtr, refCon );
  45.             break;
  46.         case kAESetData:
  47.             err = TETextSetDataHandler( tokenPtr, theAppleEventPtr, replyEventPtr, refCon );
  48.             break;
  49.         default:
  50.             err = errAEEventNotHandled;
  51.             break;
  52.     }
  53.     
  54.     return noErr;
  55. }
  56.  
  57. /*
  58.  * Event Handlers
  59.  */
  60.  
  61. /* Get Data */
  62.  
  63. OSErr TETextGetDataHandler( AEDesc *tokenPtr,
  64.                         AppleEvent *theAppleEventPtr,
  65.                         AppleEvent *replyEventPtr,
  66.                         long refCon )
  67. {
  68.     TEHandle        textH;
  69.     DescType        propCode;
  70.     short            startPos;
  71.     short            length;
  72.     TETextTokenBody    **tokHdl;
  73.     Handle            rawTextHdl;
  74.     AEDesc            replyValue;
  75.     long            rawSize;
  76.     OSErr            err;
  77.     SignedByte        hState;
  78.  
  79.     /* Sanity check */
  80.     if ( tokenPtr->descriptorType != typeTEText ){
  81.         Gripe( "\pGot wrong token type" );
  82.         return errAEEventNotHandled;
  83.     }
  84.  
  85.     tokHdl = (TETextTokenBody**)(tokenPtr->dataHandle);
  86.     
  87.     textH = (*tokHdl)->textH;
  88.     propCode = (*tokHdl)->propertyCode;
  89.     startPos = (*tokHdl)->startPos;
  90.     length = (*tokHdl)->length;
  91.     
  92.     if ( !textH ){
  93.         Gripe( "\pAttempting to get data for non-existent TextEdit Record" );
  94.         return errAENoSuchObject;
  95.     }
  96.  
  97.     switch ( propCode ){
  98.         case typeNull:
  99.             /* This is a magic number for "Not A Property".  I don't know if this
  100.              * is really kosher - gotta ask, but it is a convenience.
  101.              */
  102.             
  103.             /* return all of the text in the specified range */
  104.             rawTextHdl = (Handle)TEGetText( textH );
  105.             
  106.             /* Check the range to be sure the text is really there */
  107.             rawSize = GetHandleSize( rawTextHdl );
  108.             
  109.             if ( rawSize < startPos + length ){
  110.                 return errAECorruptData;
  111.             }
  112.             
  113.             hState = HGetState( rawTextHdl );
  114.             HLock( rawTextHdl );
  115.             
  116.             err = AECreateDesc( typeChar,
  117.                                 (char*)*rawTextHdl + startPos,
  118.                                 (Size)length,
  119.                                 &replyValue );
  120.  
  121.             HSetState( rawTextHdl, hState );
  122.  
  123.             if ( err ){
  124.                 Gripe( "\pAECreateDesc failed to create text replyValue" );
  125.                 return err;
  126.             }
  127.  
  128.             break;
  129.         case pClass:
  130.         case pColor:
  131.         case pFont:
  132.         case pPointSize:
  133.         case pScriptTag:
  134.         case pTextStyles:
  135.             Gripe( "\pGot a property type we do not yet implement" );
  136.             return errAENoSuchObject;
  137.             break;
  138.         default:
  139.             Gripe( "\pUnknown property type" );
  140.             return errAENoSuchObject;
  141.             break;
  142.     }
  143.     
  144.     /* At this point we have some kind of descriptor to stick in the reply */
  145.     
  146.     err = AEPutParamDesc( replyEventPtr,
  147.                             keyDirectObject,
  148.                             &replyValue );
  149.     if ( err ){
  150.         Gripe( "\pAEPutParamDesc failed" );
  151.         return err;
  152.     }
  153.     
  154.     /* It's not clear to me if I should dispose of the reply descriptor here or not */
  155.  
  156.     return noErr;
  157. }/* TETextGetDataHandler */
  158.  
  159. /* Set Data */
  160.  
  161. OSErr TETextSetDataHandler( AEDesc *tokenPtr,
  162.                         AppleEvent *theAppleEventPtr,
  163.                         AppleEvent *replyEventPtr,
  164.                         long refCon )
  165. {
  166.     TEHandle        textH;
  167.     DescType        propCode;
  168.     short            startPos;
  169.     short            length;
  170.     TETextTokenBody    **tokHdl;
  171.     AEDesc            newValue;
  172.     AEDesc            textValue;
  173.     SignedByte        hState;
  174.     long            newTextLen;
  175.     AEDesc            propValToken;
  176.     OSErr            err;
  177.  
  178.     /* Sanity check */
  179.     if ( tokenPtr->descriptorType != typeTEText ){
  180.         Gripe( "\pGot wrong token type" );
  181.         return errAEEventNotHandled;
  182.     }
  183.  
  184.     tokHdl = (TETextTokenBody**)(tokenPtr->dataHandle);
  185.     
  186.     textH = (*tokHdl)->textH;
  187.     propCode = (*tokHdl)->propertyCode;
  188.     startPos = (*tokHdl)->startPos;
  189.     length = (*tokHdl)->length;
  190.     
  191.     if ( !textH ){
  192.         Gripe( "\pAttempting to set data for non-existent TextEdit Record" );
  193.         return errAENoSuchObject;
  194.     }
  195.     
  196.     /* Get the value to set, whatever it is */
  197.     
  198.     err = AEGetParamDesc( theAppleEventPtr,
  199.                             keyAEData,
  200.                             typeWildCard,
  201.                             &newValue );
  202.     if ( err ){
  203.         Gripe( "\pAEGetParamDesc failed to get keyAEData" );
  204.         return err;
  205.     }                        
  206.  
  207.     switch ( propCode ){
  208.         case typeNull:
  209.             /* This is a magic number for "Not A Property".  I don't know if this
  210.              * is really kosher - gotta ask, but it is a convenience.
  211.              */
  212.             
  213.             /* Set the data in the specified range */
  214.             
  215.             /* STUB Look for the optional parameter to see where to actually
  216.              * set the text at
  217.              */
  218.             
  219.             err = AECoerceDesc( &newValue, typeChar, &textValue );
  220.             if ( err ){
  221.                 Gripe( "\pAECoerceDesc failed to coerce to text" );
  222.                 return err;
  223.             }
  224.             
  225.             TESetSelect( (long)startPos, (long)startPos + length, textH );
  226.             TEDelete( textH );
  227.             
  228.             newTextLen = GetHandleSize( textValue.dataHandle );
  229.             
  230.             hState = HGetState( textValue.dataHandle );
  231.             HLock( textValue.dataHandle );
  232.             
  233.             TEInsert( (Ptr)(*textValue.dataHandle), newTextLen, textH );
  234.             
  235.             HSetState( textValue.dataHandle, hState );
  236.             
  237.             err = AEDisposeDesc( &textValue );
  238.             if ( err ){
  239.                 Gripe( "\pAEDisposeDesc failed" );
  240.                 return err;
  241.             }
  242.             
  243.             break;
  244.  
  245.         case pBackgroundHilite:
  246.         
  247.             /* Make sure that we have an object specifier */
  248.  
  249.             err = AECoerceDesc( &newValue, typeObjectSpecifier, &textValue );
  250.             if ( err ){
  251.                 Gripe( "\pAECoerceDesc failed to coerce to typeObjectSpecifier" );
  252.                 return err;
  253.             }
  254.             
  255.             /* Resolve the object specifier to get the get the range of text to hilite */
  256.             err = AEResolve( &newValue, kAEIDoMinimum, &propValToken );
  257.             if ( err )
  258.                 return err;
  259.             
  260.             /* Check that the token is of the correct type */
  261.             if ( propValToken.descriptorType != typeTEText )
  262.                 return errAEWrongDataType;        /* They sent a token for the wrong thing */
  263.  
  264.             /* Set the selection in the TextEdit text */
  265.  
  266.             tokHdl = (TETextTokenBody**)(propValToken.dataHandle);
  267.             
  268.             TESetSelect( (*tokHdl)->startPos,
  269.                             (*tokHdl)->startPos + (*tokHdl)->length,
  270.                             textH );
  271.                             
  272.             /* Display the selection, given that we are in the background */
  273.  
  274.             TEActivate( textH );    /* (Not normally done while in background) */
  275.  
  276.             return noErr;
  277.  
  278.         case pClass:
  279.         case pColor:
  280.         case pFont:
  281.         case pPointSize:
  282.         case pScriptTag:
  283.         case pTextStyles:
  284.             Gripe( "\pGot a property type we do not yet implement" );
  285.             return errAENoSuchObject;
  286.             break;
  287.         default:
  288.             Gripe( "\pUnknown property type" );
  289.             return errAENoSuchObject;
  290.             break;
  291.     }
  292.     
  293.     /* At this point we are done with the newValue descriptor */
  294.     
  295.     err = AEDisposeDesc( &newValue );
  296.     
  297.     if ( err ){
  298.         Gripe( "\pAEDisposeDesc newValue failed" );
  299.         return err;
  300.     }
  301.  
  302.     return noErr;
  303. }/* TETextSetDataHandler */
  304.  
  305. /*
  306.  * Object Accessors
  307.  */
  308.  
  309.  
  310. /* Return a text token given a Window token */
  311.  
  312. pascal OSErr TextFromWind(DescType desiredClass,
  313.                             const AEDesc *container,
  314.                             DescType containerClass,
  315.                             DescType form,
  316.                             const AEDesc *selectionData,
  317.                             AEDesc *theToken,
  318.                             long LongInt)
  319. {
  320.     AEDesc            longKeyData;
  321.     WindowPtr        wp;
  322.     long            count;
  323.     TETextTokenBody    tokData;
  324.     Handle            rawTextHdl;
  325.     short            textLen;
  326.     TEHandle        textH;
  327.     OSErr            err;
  328.  
  329.     /* Check that the container is what we intend.  This should only happen if we
  330.      * installed the token handler incorrectly.
  331.      */
  332.  
  333.     if ( container->descriptorType != cWindow )
  334.         return errAEEventNotHandled;
  335.     
  336.     /* find the window based on the key form */
  337.     
  338.     switch ( form ){
  339.         case formAbsolutePosition:
  340.             /* Make sure we really have a type long descriptor */
  341.             err = AECoerceDesc( selectionData, typeLongInteger, &longKeyData );
  342.             if ( err ){
  343.                 Gripe( "\pAECoerceDesc failed" );
  344.                 return err;
  345.             }
  346.             
  347.             count = **(long**)(longKeyData.dataHandle);
  348.             
  349.             /* We're done with the descriptor created in the coercion */
  350.             
  351.             err = AEDisposeDesc( &longKeyData );
  352.             if ( err ){
  353.                 Gripe( "\pAEDisposeDesc failed" );
  354.                 return err;
  355.             }
  356.             
  357.             /* We only have one text field in the window */
  358.             
  359.             if ( count != 1 ){
  360.                 Gripe( "\pAttempting to get text from other than the first field" );
  361.                 return errAENoSuchObject;
  362.             }
  363.  
  364.             wp = (*(WindTokenBody**)(container->dataHandle))->theWindowPtr;
  365.             
  366.             textH = (TEHandle)GetWRefCon( wp );
  367.             
  368.             rawTextHdl = (Handle)TEGetText( textH );
  369.             textLen = (short)GetHandleSize( rawTextHdl );
  370.  
  371.             /* Actually create the token that we return */
  372.             tokData.textH = textH;
  373.             tokData.startPos = 0;
  374.             tokData.length = textLen;                /* _All_ of the text */
  375.             tokData.propertyCode = typeNull;        /* This means it's not a property */
  376.             
  377.             err = AECreateDesc( typeTEText, (Ptr)&tokData, sizeof( tokData ), theToken );
  378.             if ( err ){
  379.                 Gripe( "\pAECreateDesc failed to create a token" );
  380.                 return err;
  381.             }
  382.             
  383.             return noErr;
  384.             break;
  385.         case formRelativePosition:
  386.         case formTest:
  387.         case formRange:
  388.         case formPropertyID:
  389.             Gripe( "\pGot a formPropertyID" );
  390.             break;
  391.         case formName:
  392.             return errAEEventNotHandled;    /* Flesh this out later */
  393.             break;
  394.         default:
  395.             Gripe( "\pGot unexpected key form" );
  396.             return errAEEventNotHandled;
  397.     }
  398.         
  399.     return noErr;
  400. }
  401.  
  402. /* return a word token from a TextEdit text token.  The word is actually still a TEText */
  403.  
  404. pascal OSErr WordFromTEText(DescType desiredClass,
  405.                             const AEDesc *container,
  406.                             DescType containerClass,
  407.                             DescType form,
  408.                             const AEDesc *selectionData,
  409.                             AEDesc *theToken,
  410.                             long LongInt)
  411. {
  412.     AEDesc            longKeyData;
  413.     WindowPtr        wp;
  414.     long            count;
  415.     TETextTokenBody    tokData;
  416.     Handle            rawTextHdl;
  417.     char            *textPtr;
  418.     short            i;
  419.     short            textLen;
  420.     TEHandle        textH;
  421.     short            oldPos;
  422.     short            newPos;
  423.     short            offSet;
  424.     short            oldLength;
  425.     OSErr            err;
  426.  
  427.     /* Check that the container is what we intend.  This should only happen if we
  428.      * installed the token handler incorrectly.
  429.      */
  430.  
  431.     if ( container->descriptorType != typeTEText )
  432.         return errAEEventNotHandled;
  433.     
  434.     /* find the text based on the key form */
  435.     
  436.     switch ( form ){
  437.         case formAbsolutePosition:
  438.             /* Make sure we really have a type long descriptor */
  439.             err = AECoerceDesc( selectionData, typeLongInteger, &longKeyData );
  440.             if ( err ){
  441.                 Gripe( "\pAECoerceDesc failed" );
  442.                 return err;
  443.             }
  444.             
  445.             count = **(long**)(longKeyData.dataHandle);
  446.             
  447.             /* We're done with the descriptor created in the coercion */
  448.             
  449.             err = AEDisposeDesc( &longKeyData );
  450.             if ( err ){
  451.                 Gripe( "\pAEDisposeDesc failed" );
  452.                 return err;
  453.             }
  454.             
  455.             /* This is a really, really rude way to find a word.  Assume that
  456.              * each word is separated by just one space (we will really want to
  457.              * allow for runs of spaces or other word-separating characters.  The
  458.              * following method is basically just plain wrong, but will suffice for
  459.              * illustration.
  460.              *
  461.              * Also note that the first word in a block might come after a run of
  462.              * spaces.
  463.              */
  464.             
  465.             textH = (*(TETextTokenBody**)(container->dataHandle))->textH;
  466.  
  467.             rawTextHdl = (Handle)TEGetText( textH );
  468.             
  469.             oldPos = (*(TETextTokenBody**)(container->dataHandle))->startPos;
  470.  
  471.             textPtr = *rawTextHdl + oldPos;    /* Deref'ed a handle! */
  472.             
  473.             oldLength = (*(TETextTokenBody**)(container->dataHandle))->length;
  474.             
  475.             for ( i = oldLength ; i; i-- ){
  476.                 if ( count == 0 )                /* Hmm... thought it was 1-based */
  477.                     break;
  478.                 if ( *textPtr++ == ' ' )
  479.                     count--;
  480.             }
  481.  
  482.             if ( i == 0 ){
  483.                 Gripe( "\pRan off end of text before finding word" );
  484.                 return errAENoSuchObject;
  485.             }
  486.             
  487.             offSet = oldLength - i;
  488.             
  489.             newPos = oldPos + offSet;
  490.             
  491.             /* now find the end of the word */
  492.  
  493.             textPtr = *rawTextHdl + newPos;    /* Deref'ed a handle! */
  494.  
  495.             for ( i = oldLength - offSet ; i; i-- ){
  496.                 if ( *++textPtr == ' ' )
  497.                     break;
  498.             }
  499.             
  500.             /* Actually create the token that we return */
  501.             tokData.textH = textH;
  502.             tokData.startPos = newPos;
  503.             tokData.length = oldLength - offSet - i + 1;
  504.             tokData.propertyCode = typeNull;        /* This means it's not a property */
  505.             
  506.             err = AECreateDesc( typeTEText, (Ptr)&tokData, sizeof( tokData ), theToken );
  507.             if ( err ){
  508.                 Gripe( "\pAECreateDesc failed to create a token" );
  509.                 return err;
  510.             }
  511.             
  512.             return noErr;
  513.             break;
  514.         case formRelativePosition:
  515.         case formTest:
  516.         case formRange:
  517.         case formPropertyID:
  518.         case formName:
  519.             return errAEEventNotHandled;    /* Flesh this out later */
  520.             break;
  521.         default:
  522.             Gripe( "\pGot unexpected key form" );
  523.             return errAEEventNotHandled;
  524.     }
  525.         
  526.     return noErr;
  527. }
  528.  
  529. /* Return a textedit char token given a textedit text token */
  530.  
  531. pascal OSErr CharFromTEText(DescType desiredClass,
  532.                             const AEDesc *container,
  533.                             DescType containerClass,
  534.                             DescType form,
  535.                             const AEDesc *selectionData,
  536.                             AEDesc *theToken,
  537.                             long LongInt)
  538. {
  539.     AEDesc            startSpec;
  540.     AEDesc            endSpec;
  541.     AEDesc            rangeRecord;
  542.     AEDesc            startToken;
  543.     AEDesc            endToken;
  544.     long            count;
  545.     AEDesc            longKeyData;
  546.     TEHandle        textH;
  547.     Handle            rawTextHdl;
  548.     long            numRawChars;
  549.     TETextTokenBody    tokData;
  550.     short            offset;
  551.     OSErr            err;
  552.  
  553.     /* Check that the container is what we intend.  This should only happen if we
  554.      * installed the token handler incorrectly.
  555.      */
  556.  
  557.     if ( container->descriptorType != typeTEText )
  558.         return errAEEventNotHandled;
  559.     
  560.     /* find the text based on the key form */
  561.     
  562.     switch ( form ){
  563.         case formAbsolutePosition:
  564.             /* Make sure we really have a type long descriptor */
  565.             err = AECoerceDesc( selectionData, typeLongInteger, &longKeyData );
  566.             if ( err ){
  567.                 Gripe( "\pAECoerceDesc failed" );
  568.                 return err;
  569.             }
  570.             
  571.             count = **(long**)(longKeyData.dataHandle);
  572.             
  573.             /* We're done with the descriptor created in the coercion */
  574.             
  575.             err = AEDisposeDesc( &longKeyData );
  576.             if ( err ){
  577.                 Gripe( "\pAEDisposeDesc failed" );
  578.                 return err;
  579.             }
  580.  
  581.             textH = (*(TETextTokenBody**)(container->dataHandle))->textH;
  582.  
  583.             rawTextHdl = (Handle)TEGetText( textH );
  584.             
  585.             numRawChars = GetHandleSize( rawTextHdl );
  586.             
  587.             if ( count > 0 ){
  588.                 /* The position is relative to the beginning */
  589.                 if ( count > numRawChars ){
  590.                     Gripe( "\pAsked for character past end" );
  591.                     return errAENoSuchObject;        /* Wanted char that was past end */
  592.                 }
  593.                 
  594.                 offset = (short) count;
  595.     
  596.             } else {
  597.                 /* In this case, the position is relative to the end of the text */
  598.  
  599.                 if ( count < -numRawChars ){
  600.                     Gripe( "\pAsked for character before beginning" );
  601.                     return errAENoSuchObject;
  602.                 }
  603.                 
  604.                 offset = (short)(numRawChars + count);        /* Note that count is negative */
  605.             }
  606.             /* Actually create the token that we return. */
  607.             
  608.             tokData.textH = textH;
  609.             tokData.startPos = offset;
  610.             tokData.length = 1;                        /* formAbs can have only 1 char */
  611.             tokData.propertyCode = typeNull;        /* This means it's not a property */
  612.  
  613.             err = AECreateDesc( typeTEText, (Ptr)&tokData, sizeof( tokData ), theToken );
  614.             if ( err ){
  615.                 Gripe( "\pAECreateDesc failed to create a token" );
  616.                 return err;
  617.             }
  618.  
  619.             return noErr;
  620.             break;
  621.         case formRelativePosition:
  622.             return errAEEventNotHandled;
  623.             break;
  624.         case formTest:
  625.             return errAEEventNotHandled;
  626.             break;
  627.         case formRange:
  628.  
  629.             /* We must coerce the spec to an AERecrd so GetKeyDesc will know what
  630.              * to do with it.
  631.              */
  632.             
  633.             err = AECoerceDesc( selectionData,
  634.                             typeAERecord,
  635.                             &rangeRecord );
  636.             if ( err )
  637.                 return err;
  638.  
  639.             err = AEGetKeyDesc( &rangeRecord,
  640.                                 keyAERangeStart,
  641.                                 typeObjectSpecifier,
  642.                                 &startSpec );
  643.             if ( err ){
  644.                 Gripe( "\pAEGetKeyDesc failed" );
  645.                 return err;
  646.             }
  647.             
  648.             err = AEGetKeyDesc( &rangeRecord,
  649.                                 keyAERangeStop,
  650.                                 typeObjectSpecifier,
  651.                                 &endSpec );
  652.             if ( err ){
  653.                 Gripe( "\pAEGetKeyDesc failed" );
  654.                 return err;
  655.             }
  656.             
  657.             /* Now we have the object specifiers for the beginning and end of the
  658.              * range.  We call AEResolve to give us tokens for the items that are
  659.              * at each end.  Note that this causes two recursive calls to this very
  660.              * function.
  661.              */
  662.  
  663.             err = AEResolve( &startSpec, kAEIDoMinimum, &startToken );
  664.             if ( err )
  665.                 return err;
  666.             
  667.             err = AEResolve( &endSpec, kAEIDoMinimum, &endToken );
  668.             if ( err )
  669.                 return err;
  670.             
  671.  
  672.             /* Create the return token */
  673.             tokData.textH = (*(TETextTokenBody**)(container->dataHandle))->textH;
  674.             
  675.             tokData.startPos = (*(TETextTokenBody**)(startToken.dataHandle))->startPos;
  676.             tokData.length = (*(TETextTokenBody**)(endToken.dataHandle))->startPos -
  677.                                 (*(TETextTokenBody**)(startToken.dataHandle))->startPos;
  678.  
  679.             tokData.propertyCode = typeNull;        /* This means it's not a property */
  680.  
  681.             err = AECreateDesc( typeTEText, (Ptr)&tokData, sizeof( tokData ), theToken );
  682.             if ( err ){
  683.                 Gripe( "\pAECreateDesc failed to create a token" );
  684.                 return err;
  685.             }
  686.  
  687.             return noErr;
  688.             break;
  689.         case formPropertyID:
  690.             return errAEEventNotHandled;
  691.             break;
  692.         case formName:
  693.             return errAEEventNotHandled;    /* Flesh this out later */
  694.             break;
  695.         default:
  696.             Gripe( "\pGot unexpected key form" );
  697.             return errAEEventNotHandled;
  698.     }
  699.         
  700.     return noErr;
  701. }
  702.  
  703. /* Return a property token given a textedit text token.
  704.  * This works for any property of a textedit text item
  705.  */
  706.  
  707. pascal OSErr PropFromTEText(DescType desiredClass,
  708.                             const AEDesc *container,
  709.                             DescType containerClass,
  710.                             DescType form,
  711.                             const AEDesc *selectionData,
  712.                             AEDesc *theToken,
  713.                             long LongInt)
  714. {
  715.     OSErr                err;
  716.     DescType            propType;
  717.  
  718.     /* Check that the container is what we intend.  This should only happen if we
  719.      * installed the token handler incorrectly.
  720.      */
  721.  
  722.     if ( container->descriptorType != typeTEText )
  723.         return errAEEventNotHandled;
  724.  
  725.     if ( form != formPropertyID ){
  726.         Gripe( "\pExpected formPropertyID" );
  727.         return errAEEventNotHandled;
  728.     }
  729.  
  730.     propType = **( (DescType**)(selectionData->dataHandle) );
  731.  
  732.     /* All we really do here is shove the property type into the token, if we
  733.      * know about the property type
  734.      */
  735.  
  736.     switch ( propType ){
  737.         case pBackgroundHilite:
  738.             /* This property contains a selection which is displayed while in the
  739.              * background.  All we do here is set the property code in the token
  740.              * (This is done after the switch).
  741.              */
  742.             break;
  743.         case pClass:
  744.         case pColor:
  745.         case pFont:
  746.         case pPointSize:
  747.         case pScriptTag:
  748.         case pTextStyles:
  749.             Gripe( "\pGot a property type we do not yet implement" );
  750.             return errAENoSuchObject;
  751.             break;
  752.         default:
  753.             Gripe( "\pUnknown property type" );
  754.             return errAENoSuchObject;
  755.             break;
  756.     }
  757.  
  758.     /* All we do in the token is put the propType into it.  We can start with the
  759.      * container descriptor as it has some of the fields filled in already.
  760.      */
  761.     
  762.     err = AEDuplicateDesc( container, theToken );
  763.     if ( err ){
  764.         Gripe( "\pAEDuplicateDesc failed" );
  765.         return err;
  766.     }
  767.     
  768.     (*(TETextTokenBody**)(theToken->dataHandle))->propertyCode = propType;
  769.     
  770.     return noErr;
  771. }
  772.  
  773. /*
  774.  * Coercion handlers
  775.  */
  776.  
  777. /* Convert a pointer to raw text to a Pascal string.  This is such a simple one it
  778.  * ought to have been built into the system!
  779.  */
  780.  
  781. pascal OSErr TextPtrToPString( DescType typeCode,
  782.                                 Ptr dataPtr,
  783.                                 Size dataSize,
  784.                                 DescType toType,
  785.                                 long handlerRefCon,
  786.                                 AEDesc *resultPtr )
  787. {
  788.     char    *buf;
  789.     OSErr    err;
  790.     Ptr        myDataPtr;
  791.     Size    myDataSize;
  792.  
  793.     if ( toType != typePString )
  794.         return errAECoercionFail;
  795.  
  796.     /* This one routine could reasonably coerce from several different sorts of textual
  797.      * data.  We switch off the types and set a pointer to where the text data actually
  798.      * starts.  Don't have any "from" types but typeChar so far.
  799.      */
  800.  
  801.     switch ( typeCode ){
  802.         case typeChar:
  803.             myDataPtr = dataPtr;
  804.             myDataSize = dataSize;
  805.             break;
  806.         default:
  807.             Gripe( "\pCannot coerce requested type" );
  808.             return errAECoercionFail;
  809.             break;
  810.     }
  811.  
  812.     if ( myDataSize > 255 || myDataSize < 0 )
  813.         return errAECoercionFail;
  814.  
  815.     buf = NewPtr( myDataSize + 1 );
  816.     if ( !buf )
  817.         return memFullErr;
  818.     
  819.     buf[0] = myDataSize;
  820.     BlockMove( myDataPtr, &(buf[1]), dataSize );
  821.     
  822.     err = AECreateDesc( typePString,
  823.                         buf,
  824.                         myDataSize + 1,
  825.                         resultPtr );
  826.                         
  827.     return err;
  828. }
  829.